package luob.study;

import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

public class MyProxy {
	public static Object newProxyInstance(Class<?> interf,
			InvocationHandler handler) throws Exception {
		String rt = "\r\n";
		String dyClassName = interf.getName().substring(
				interf.getName().lastIndexOf(".") + 1)
				+ "proxy";

		String methodSrc = "";
		for (Method m : interf.getMethods()) {
			String dyMethodName = m.toString().replace("abstract", "")
					.replace(interf.getName() + ".", "");
			String[] sps = dyMethodName.split(",");
			String pnames = "";
			String pclassNames = "";
			if (m.getParameterCount() > 0) {
				String temp = "";
				for (int i = 0; i < sps.length; i++) {
					if (i == sps.length - 1) {
						temp += (sps[i].replace(")", " p" + i + ")"));
						pnames += (" p" + i);
					} else {
						temp += (sps[i] + " p" + i + ",");
						pnames += (" p" + i + ",");
					}
				}
				dyMethodName = temp;

				for (Class<?> p : m.getParameterTypes()) {
					pclassNames += (p.getTypeName() + ".class,");
				}
				pclassNames = pclassNames
						.substring(0, pclassNames.length() - 1);

			}
			methodSrc += ("@Override" + rt + dyMethodName + " {" + rt
					+ "Method m;" + rt + "try {" + rt
					+ "m = luob.study.Movable.class.getMethod(\"" + m.getName()
					+ "\", new Class[] {" + pclassNames + "});" + rt
					+ "t.invoke(this, m,new Object[]{" + pnames + "});" + rt
					+ "} catch (Exception e) {" + rt + "}" + rt + "}");
		}
		String src = "import java.lang.reflect.Method;" + rt +

		"public class " + dyClassName + " implements " + interf.getName() + "{"
				+ rt +

				"luob.study.InvocationHandler t;" + rt + "" +

				"public " + dyClassName + "(luob.study.InvocationHandler t) {"
				+ rt + "super();" + rt + "this.t = t;" + rt + "}" + rt +

				methodSrc +

				"}";

		String filePath = System.getProperty("user.dir") + "/src/"
				+ dyClassName + ".java";// =/Users/luob_dev/eclipse_std/workspace/Proxy
		File file = new File(filePath);
		FileWriter fw = new FileWriter(file);
		fw.write(src);
		fw.flush();
		fw.close();

		// compile dynamic src
		JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
		StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null,
				null, null);
		Iterable<? extends JavaFileObject> compilationUnits = fileMgr
				.getJavaFileObjects(filePath);
		CompilationTask task = compiler.getTask(null, fileMgr, null, null,
				null, compilationUnits);
		task.call();

		// load class file, and new instance
		URL[] urls = new URL[] { new URL("file:/"
				+ System.getProperty("user.dir")) };
		URLClassLoader loader = new URLClassLoader(urls);
		Class<?> c = loader.loadClass(dyClassName);
		loader.close();

		Constructor<?> constructor = c
				.getConstructor(new Class[] { InvocationHandler.class });
		Object o = constructor.newInstance(handler);

		return o;
	}
}
